home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 05 - 1989 / 05.02 Feb 89 / security code / Globals.Pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1988-11-29  |  34.4 KB  |  1,484 lines  |  [TEXT/MPS ]

  1. UNIT  Globals;
  2. {-------------------------------------------}
  3. (*
  4. ©1988 by Steve Seaquist. All rights reserved.
  5. Used by permission.  Use at your own risk.  
  6. No warranty is expressed or implied.  
  7.  
  8. This Macintosh virus-detecting program was 
  9. originally published and explained in the 
  10. February 1989 issue of MacTutor magazine.  
  11. Some aspects of its design are important to 
  12. security, and it uses some unusual 
  13. techniques, so please read the article.  
  14. *)
  15. {-------------------------------------------}
  16. INTERFACE
  17. USES
  18.   MacIntf,BitProcs;
  19.  
  20. CONST
  21.   {---- Low Mem Globals ----}
  22.   kCurApName          = $910;
  23.   kCurApRefNum        = $900;
  24.   kBootDrive          = $210;
  25.   kResLoad            = $A5E;
  26.   kScrDmpEnb          = $2F8;
  27.   kSFCBLen            = $3F6;
  28.   kSPConfig           = $1FB;
  29.   kSysMap             = $A58;
  30.   kSysResName         = $AD8;
  31.   {---- Other constants ----}
  32.   kIOBufferSize       = 10000;
  33.   kProcessSelf        = FALSE;
  34.   kRsrcHdlValid       = 9876543;
  35.   kRsrcIsInitd        = 3456789;
  36.   kZeroOutVirs        = TRUE;
  37.  
  38. TYPE
  39.   TCountsPtr          = ^TCountsRec;
  40.   TCountsRec          =
  41.     RECORD
  42.     fDeleted:         LONGINT;
  43.     fExamined:        LONGINT;
  44.     fFiles:           LONGINT;
  45.     fInfected:        LONGINT;
  46.     fRemoved:         LONGINT;
  47.     fResources:       LONGINT;
  48.     END;
  49.  
  50.   TFeedbackPtr        = ^TFeedbackRec;
  51.   TFeedbackRec        =
  52.     PACKED RECORD
  53.     fWroteDirname:    BOOLEAN;
  54.     fWroteFilename:   BOOLEAN;
  55.     END;
  56.  
  57.   TJTEHdl             = ^TJTEPtr;
  58.   TJTEPtr             = ^TJTERec;
  59.   TJTERec             =
  60.     RECORD
  61.     fOffset:          INTEGER;
  62.     fSkip3F3C:        INTEGER;
  63.     fSegId:           INTEGER;
  64.     fSkipA9F0:        INTEGER;
  65.     END;
  66.  
  67.   TJTHdl              = ^TJTPtr;
  68.   TJTPtr              = ^TJTRec;
  69.   TJTRec              =
  70.     RECORD
  71.     fAboveA5Size:     LONGINT;
  72.     fBelowA5Size:     LONGINT;
  73.     fNbrBytesInTable: LONGINT;
  74.     fTableOffset:     LONGINT;
  75.     fJTEntry:         
  76.       ARRAY [1..1] OF TJTERec;
  77.     END;
  78.  
  79.   TLoaded             = 
  80.     (eNotYet,eAlreadyLoaded,eWeLoadedIt);
  81.  
  82.   TMainItem           = 
  83.     (eNotADlogItem,
  84.     eDirs,eDiry,eEvery,eFiles,eQuit,
  85.     eAwait,eBeeps,eFgPr,eFgPrC,
  86.     eLList,eRmVir,eTrace,
  87.     eMain,eOpts,eScOW, 
  88.     eDBtn);
  89.   TMainOpt            = 
  90.     ARRAY [eAwait..eTrace] OF BOOLEAN;
  91.  
  92.   TPaocRec            = 
  93.     PACKED ARRAY[1..1] OF CHAR;
  94.   TResIdOrIndex       = (ResId,Index);
  95.  
  96.   TRsrcPtr            = ^TRsrcRec;
  97.   TRsrcRec            =
  98.     RECORD
  99.     fFlag:            LONGINT;
  100.     fHdl:             Handle;
  101.     fInfected:        BOOLEAN;
  102.     fKnown:           BOOLEAN;
  103.     fLoaded:          TLoaded;
  104.     fResAttrs:        INTEGER;
  105.     fResId:           INTEGER;
  106.     fResType:         ResType;
  107.     fSize:            Size;
  108.     fState:           SignedByte;
  109.     END;
  110.  
  111.   TScoresHdl          = ^TScoresPtr;
  112.   TScoresPtr          = ^TScoresRec;
  113.   TScoresRec          =
  114.     RECORD
  115.     fOffsetToFirstJTE:INTEGER;
  116.     fNbrJTEsForRsrc:  INTEGER;
  117.     fOldJTE:          TJTERec;
  118.     END;
  119.  
  120.   TWordHdl            = ^TWordPtr;
  121.   TWordPtr            = ^INTEGER;
  122.  
  123. VAR
  124.   gAAGlobals:         SignedByte;
  125.   gAbortPatrol:       BOOLEAN;
  126.   gActiveSelf:        BOOLEAN;
  127.   gActiveSys:         BOOLEAN;
  128.   gCode0:             TRsrcRec;
  129.   gCounts:            TCountsRec;
  130.   gCurrDInfo:         DInfo;
  131.   gCurrDirId:         LONGINT;
  132.   gCurrDirname:       Str255;
  133.   gCurrEOF:           LONGINT;
  134.   gCurrIOBuffer:      Ptr;
  135.   gCurrFileDeleted:   BOOLEAN;
  136.   gCurrFilename:      Str255;
  137.   gCurrFInfo:         FInfo;
  138.   gCurrIndex:         INTEGER;
  139.   gCurrRefNum:        INTEGER;
  140.   gCurrRsrc:          TRsrcRec;
  141.   gCurrVRefNum:       INTEGER;
  142.   gCurrWDRefNum:      INTEGER;
  143.   gDateTimeRec:       DateTimeRec;
  144.   gDisabled:          TMainOpt;
  145.   gDlogPtr:           DialogPtr;
  146.   gError:             OSErr;
  147.   gEvt:               EventRecord;
  148.   gEvtMask:           INTEGER;
  149.   gFgPrTitle:         Str255;
  150.   gGrafPtr:           GrafPtr;
  151.   gHFS:               BOOLEAN;
  152.   gInd:               STRING[10];
  153.   gInfected:          BOOLEAN;
  154.   gInfectedWritten:   BOOLEAN;
  155.   gOption:            TMainOpt;
  156.   gPgmrname:          Str255;
  157.   gReportFlags:       TFeedbackRec;
  158.   gScreenFlags:       TFeedbackRec;
  159.   gSecsBegins:        LONGINT;
  160.   gSecsEnds:          LONGINT;
  161.   gSFGetPt:           Point;
  162.   gSFPutPt:           Point;
  163.   gSFRep:             SFReply;
  164.   gTotals:            TCountsRec;
  165.   gZZGlobals:         SignedByte;
  166.  
  167. FUNCTION   Code0IsValid
  168.   :          BOOLEAN;
  169. PROCEDURE  CommentBegins;
  170. PROCEDURE  CommentFgPrRsrc
  171.   (pRsrcPtr: TRsrcPtr);
  172. PROCEDURE  CommentRsrcBegins
  173.   (pRsrcPtr: TRsrcPtr);
  174. PROCEDURE  DirectoryBegins;
  175. PROCEDURE  DirectoryEnds;
  176. PROCEDURE  ErrorBegins
  177.   (pStr:     Str255);
  178. PROCEDURE  ErrorEnds
  179.   (pBeeps:   INTEGER);
  180. PROCEDURE  ErrorOSErr
  181.   (pStr:     Str255);
  182. PROCEDURE  GetRsrc
  183.   (pRsrcPtr: TRsrcPtr;
  184.   pResType:  ResType;
  185.   pInt:      INTEGER;
  186.   pIntIs:    TResIdOrIndex);
  187. PROCEDURE  InitGlobals;
  188. PROCEDURE  InitRsrc
  189.   (pRsrcPtr: TRsrcPtr);
  190. FUNCTION   JTEIsValid
  191.   (pJTEPtr:  TJTEPtr)
  192.   :          BOOLEAN;
  193. PROCEDURE  ListCounts
  194.   (pPtr:     TCountsPtr);
  195. PROCEDURE  LookForKnownViruses;
  196. PROCEDURE  PauseBriefly;
  197. PROCEDURE  PatrolBegins;
  198. PROCEDURE  PatrolEnds;
  199. PROCEDURE  ProcessCurrRsrc;
  200. PROCEDURE  ProcessFile;
  201. PROCEDURE  ReleaseRsrc
  202.   (pRsrcPtr: TRsrcPtr);
  203. PROCEDURE  ShortHexDump
  204.   (pPtr:     Ptr;
  205.   pNbrBytes: SignedByte);
  206. PROCEDURE  Trace
  207.   (pStr:    Str255);
  208. PROCEDURE  TraceNbr
  209.   (pStr:     Str255;
  210.   pNbr:      LONGINT);
  211. PROCEDURE  ZeroOut
  212.   (pStart:   Ptr;
  213.   pCount:    Size);
  214. PROCEDURE  ZeroOutRange
  215.   (p1:       Ptr;
  216.   p2:        Ptr);
  217.  
  218. {*******************************************}
  219. IMPLEMENTATION
  220. {$R-}
  221.  
  222. PROCEDURE  ExitSecurityPatrol;      EXTERNAL;
  223. PROCEDURE  Wryte
  224.   (pStr:     Str255);               EXTERNAL;
  225. PROCEDURE  WryteChar
  226.   (pChar:    CHAR);                 EXTERNAL;
  227. PROCEDURE  WryteEoln;               EXTERNAL;
  228. PROCEDURE  WryteFilename;           EXTERNAL;
  229. PROCEDURE  WryteFilenameToScreenOnlyForNow;
  230.                                     EXTERNAL;
  231. PROCEDURE  WryteLn
  232.   (pStr:     Str255);               EXTERNAL;
  233. PROCEDURE  WryteNbr
  234.   (pNbr:     LONGINT;
  235.   pNbrDigits:INTEGER);              EXTERNAL;
  236. PROCEDURE  WryteType
  237.   (pType:    ResType);              EXTERNAL;
  238.  
  239. PROCEDURE  CallProcPtr
  240.   (pProcPtr: ProcPtr);
  241. INLINE
  242.   $205F,     { MOVE.L (A7)+,A0 }
  243.   $4E90;     { JSR    (A0)     }
  244.  
  245. PROCEDURE  ErrorInfected
  246.   (pStr:     Str255);                FORWARD;
  247. PROCEDURE  ErrorMsg
  248.   (pStr:     Str255;
  249.   pBeeps:    INTEGER);               FORWARD;
  250. FUNCTION   FixedCode0
  251.   (pJTPtr:   TJTEPtr)
  252.   :          BOOLEAN;                FORWARD;
  253. PROCEDURE  ProcessRsrcs
  254.   (pResType: ResType;
  255.   pProcPtr:  ProcPtr);               FORWARD;
  256. FUNCTION   RemovedRsrc
  257.   (pRsrcPtr: TRsrcPtr)
  258.   :          BOOLEAN;                FORWARD;
  259. PROCEDURE  TraceRsrc
  260.   (pStr:     Str255;
  261.   pRsrcPtr:  TRsrcPtr);              FORWARD;
  262.  
  263. {$S Fingerprint}
  264. {$I Fingerprint.ipas }
  265. {$S Globals}
  266. {-------------------------------------------}
  267. PROCEDURE  AbortPatrolIfCmdPeriodPressed;
  268. BEGIN
  269. WHILE GetNextEvent(gEvtMask,gEvt) DO
  270.   WITH gEvt DO
  271.     IF  (what = nullEvent) THEN
  272.       LEAVE
  273.     ELSE IF (what = keyDown) THEN
  274.       IF  (BAnd(modifiers,cmdKey)=cmdKey)
  275.       AND (BAnd(message,charCodeMask)=$2E)
  276.       THEN
  277.         BEGIN
  278.         gAbortPatrol := TRUE;
  279.         WryteLn('Patrol aborted');
  280.         LEAVE;
  281.         END;
  282. END;
  283. {-------------------------------------------}
  284. PROCEDURE  AwaitKeypress;
  285. BEGIN
  286. WHILE TRUE DO
  287.   BEGIN
  288.   IF NOT(GetNextEvent(gEvtMask,gEvt)) THEN
  289.     CYCLE;
  290.   WITH gEvt DO
  291.     IF (what = keyDown) THEN
  292.       BEGIN
  293.       IF  (BAnd(modifiers,cmdKey)=cmdKey)
  294.       AND (BAnd(message,charCodeMask)=$2E)
  295.       THEN
  296.         BEGIN
  297.         gAbortPatrol := TRUE;
  298.         WryteLn('Patrol aborted');
  299.         END;
  300.       LEAVE;
  301.       END;
  302.   END;
  303. END;
  304. {-------------------------------------------}
  305. FUNCTION   Code0IsValid
  306.   :          BOOLEAN;
  307. BEGIN
  308. IF  gOption[eTrace] THEN
  309.   Trace('Code0IsValid');
  310. WITH TJTHdl(gCode0.fHdl)^^ DO
  311.   Code0IsValid := 
  312.     (gCode0.fSize     >= 24)    AND
  313.     (fAboveA5Size     >= 40)    AND
  314.     (fNbrBytesInTable >=  8)    AND
  315.     (fTableOffset     =  32)    AND
  316.     (fAboveA5Size = fNbrBytesInTable+32) AND
  317.     ((fNbrBytesInTable MOD 8) = 0);
  318. END;
  319. {-------------------------------------------}
  320. PROCEDURE  CommentBegins;
  321. BEGIN
  322. Wryte(gInd);
  323. Wryte(gInd);
  324. Wryte(gInd);
  325. END;
  326. {-------------------------------------------}
  327. PROCEDURE  CommentRsrcBegins
  328.   (pRsrcPtr: TRsrcPtr);
  329. BEGIN
  330. CommentBegins;
  331. WITH pRsrcPtr^ DO
  332.   BEGIN
  333.   WryteType(fResType);
  334.   WryteNbr (fResId,7);
  335.   Wryte    (' (');
  336.   ShortHexDump(Ptr(ORD4(@fResAttrs)+1),1);
  337.   WryteChar(')');
  338.   END;
  339. END;
  340. {-------------------------------------------}
  341. PROCEDURE  CountInfected;
  342. BEGIN
  343. IF  gOption[eTrace] THEN
  344.   Trace('CountInfected');
  345. INC(gCounts.fInfected);
  346. INC(gTotals.fInfected);
  347. END;
  348. {-------------------------------------------}
  349. PROCEDURE  DirectoryBegins;
  350. BEGIN
  351. IF  gOption[eTrace] THEN
  352.   Trace('DirectoryBegins');
  353. gReportFlags.fWroteDirname := FALSE;
  354. gScreenFlags.fWroteDirname := FALSE;
  355. END;
  356. {-------------------------------------------}
  357. PROCEDURE  DirectoryEnds;
  358. BEGIN
  359. IF  gOption[eTrace] THEN
  360.   Trace('DirectoryEnds');
  361. (*
  362. Wryte  ('End of ');
  363. WryteLn(gCurrDirname);
  364. *)
  365. END;
  366. {-------------------------------------------}
  367. FUNCTION   Disinfected_nVIR
  368.   :          BOOLEAN;
  369. VAR
  370.   snVIR2:    TRsrcRec;
  371.   sCodeGone: BOOLEAN;
  372. BEGIN
  373. IF  gOption[eTrace] THEN
  374.   Trace('Disinfected_nVIR');
  375. Disinfected_nVIR := FALSE;
  376. InitRsrc(@snVIR2);
  377. GetRsrc (@snVIR2,'nVIR',2,ResId);
  378. WITH snVIR2 DO
  379.   BEGIN
  380.   IF  (fFlag <> kRsrcHdlValid) THEN
  381.     BEGIN
  382.     ErrorInfected('No nVIR 2!');
  383.     ReleaseRsrc(@gCurrRsrc);
  384.     EXIT(Disinfected_nVIR);
  385.     END;
  386.   IF  (fSize < 8) THEN
  387.     BEGIN
  388.     ErrorInfected('Too small nVIR 2!');
  389.     ReleaseRsrc(@gCurrRsrc);
  390.     ReleaseRsrc(@snVIR2);
  391.     EXIT(Disinfected_nVIR);
  392.     END;
  393.   MoveHHi(fHdl);
  394.   HLock  (fHdl);
  395.   IF  NOT(FixedCode0(TJTEPtr(fHdl^))) THEN
  396.     BEGIN
  397.     ReleaseRsrc(@gCurrRsrc);
  398.     ReleaseRsrc(@snVIR2);
  399.     EXIT(Disinfected_nVIR);
  400.     END;
  401.   Disinfected_nVIR := TRUE;
  402.   sCodeGone := RemovedRsrc(@gCurrRsrc);
  403.   ReleaseRsrc(@snVIR2);
  404.   ProcessRsrcs('nVIR',@ProcessRemoveRsrc);
  405.   IF  sCodeGone 
  406.   AND (Count1Resources('nVIR') = 0) THEN
  407.     ErrorMsg('nVIR removed',0)
  408.   ELSE
  409.     BEGIN
  410.     ErrorMsg('nVIR “disinfected”:',0);
  411.     CommentBegins;
  412.     Wryte  ('All of its resources are now ');
  413.     Wryte  ('harmless, but some were not ');
  414.     WryteLn('removed, for some reason.');
  415.     END;
  416.   END;
  417. END;
  418. {-------------------------------------------}
  419. FUNCTION   Disinfected_Scores
  420.   :          BOOLEAN;
  421. BEGIN
  422. IF  gOption[eTrace] THEN
  423.   Trace('Disinfected_Scores');
  424. Disinfected_Scores := FALSE;
  425. WITH gCurrRsrc DO
  426.   BEGIN
  427.   MoveHHi(fHdl);
  428.   HLock  (fHdl);
  429.   WITH TScoresHdl(fHdl)^^ DO
  430.     IF  NOT(FixedCode0(@fOldJTE)) THEN
  431.       BEGIN
  432.       ReleaseRsrc(@gCurrRsrc);
  433.       EXIT(Disinfected_Scores);
  434.       END;
  435.   Disinfected_Scores := TRUE;
  436.   IF  RemovedRsrc(@gCurrRsrc) THEN
  437.     ErrorMsg('Scores removed',0)
  438.   ELSE
  439.     ErrorMsg('Scores disinfected',0);
  440.   END;
  441. END;
  442. {-------------------------------------------}
  443. PROCEDURE  ErrorBegins
  444.   (pStr:     Str255);
  445. BEGIN
  446. WryteFilename;
  447. Wryte  (gInd);
  448. Wryte  (gInd);
  449. Wryte  (pStr);
  450. END;
  451. {-------------------------------------------}
  452. PROCEDURE  ErrorEnds
  453.   (pBeeps:   INTEGER);
  454. VAR
  455.   i:         INTEGER;
  456.   sBeeps:    INTEGER;
  457. BEGIN
  458. IF  gOption[eBeeps] THEN
  459.   BEGIN
  460.   IF  (pBeeps > 4) THEN
  461.     sBeeps := 4
  462.   ELSE
  463.     sBeeps := pBeeps;
  464.   FOR i := 1 TO sBeeps DO
  465.     SysBeep(3);
  466.   END;
  467. IF  gOption[eAwait] THEN
  468.   BEGIN
  469.   WryteLn(' (WAITING ON KEY PRESS)');
  470.   AwaitKeypress;
  471.   END
  472. ELSE
  473.   WryteEoln;
  474. END;
  475. {-------------------------------------------}
  476. PROCEDURE  ErrorInfected
  477.   (pStr:     Str255);
  478. BEGIN
  479. IF  NOT(gInfectedWritten) THEN
  480.   BEGIN
  481.   ErrorBegins('**!INFECTED!** ');
  482.   WryteEoln;
  483.   gInfectedWritten := TRUE;
  484.   END;
  485. IF  (pStr <> '') THEN
  486.   BEGIN
  487.   CommentBegins;
  488.   Wryte(pStr);
  489.   ErrorEnds(3);
  490.   END;
  491. END;
  492. {-------------------------------------------}
  493. PROCEDURE  ErrorMsg
  494.   (pStr:     Str255;
  495.   pBeeps:    INTEGER);
  496. BEGIN
  497. ErrorBegins(pStr);
  498. ErrorEnds(pBeeps);
  499. END;
  500. {-------------------------------------------}
  501. PROCEDURE  ErrorOSErr
  502.   (pStr:     Str255);
  503. BEGIN
  504. IF  (pStr <> '') THEN
  505.   BEGIN
  506.   ErrorBegins(pStr);
  507.   WryteEoln;
  508.   END;
  509. CommentBegins;
  510. Wryte   ('OSErr code = ');
  511. WryteNbr(gError,1);
  512. ErrorEnds(2);
  513. END;
  514. {-------------------------------------------}
  515. FUNCTION   FixedCode0
  516.   (pJTPtr:   TJTEPtr)
  517.   :          BOOLEAN;
  518. BEGIN
  519. FixedCode0 := FALSE;
  520. IF  gOption[eTrace] THEN
  521.   Trace('FixedCode0');
  522. IF  NOT(JTEIsValid(pJTPtr)) THEN
  523.   BEGIN
  524.   ErrorInfected('Bad Jump Table Entry!');
  525.   EXIT(FixedCode0);
  526.   END;
  527. IF  NOT(gOption[eRmVir]) THEN
  528.   BEGIN
  529.   ErrorInfected('Remove option off');
  530.   CommentBegins;
  531.   WITH pJTPtr^ DO
  532.     BEGIN
  533.     Wryte   ('Jumps to ');
  534.     WryteNbr(fOffset,1);
  535.     Wryte   (' of CODE ');
  536.     WryteNbr(fSegId,1);
  537.     WryteEoln;
  538.     END;
  539.   ErrorMsg('Not removed',1);
  540.   EXIT(FixedCode0);
  541.   END;
  542. WITH gCode0 DO
  543.   BEGIN
  544.   IF  gOption[eTrace] THEN
  545.     BEGIN
  546.     Trace('About to restore CODE 0');
  547.     AbortPatrolIfCmdPeriodPressed;
  548.     IF  gAbortPatrol THEN
  549.       EXIT(FixedCode0);
  550.     END;
  551.   TJTHdl(fHdl)^^.fJTEntry[1] := pJTPtr^;
  552.   IF  (BAnd(fResAttrs,resProtected) <> 0)
  553.   AND (fResAttrs <> -1) THEN
  554.     BEGIN
  555.     SetResAttrs(fHdl,0);
  556.     ChangedResource(fHdl);
  557.     gError := ResError;
  558.     SetResAttrs(fHdl,fResAttrs);
  559.     END
  560.   ELSE
  561.     BEGIN
  562.     ChangedResource(fHdl);
  563.     gError := ResError;
  564.     END;
  565.   IF  (gError <> NoErr) THEN
  566.     BEGIN
  567.     ErrorInfected('CODE 0 unchanged!');
  568.     IF  (gError = wPrErr) THEN
  569.       ErrorMsg('Disk is locked',0)
  570.     ELSE
  571.       ErrorOSErr('');
  572.     gError := 0;
  573.     EXIT(FixedCode0);
  574.     END;
  575.   WriteResource(fHdl);
  576.   gError := ResError;
  577.   IF  (gError <> NoErr) THEN
  578.     BEGIN
  579.     ErrorInfected('CODE 0 unwritten!');
  580.     ErrorOSErr('');
  581.     EXIT(FixedCode0);
  582.     END;
  583.   END;
  584. FixedCode0 := TRUE;
  585. END;
  586. {-------------------------------------------}
  587. PROCEDURE  GetRsrc
  588.   (pRsrcPtr: TRsrcPtr;
  589.   pResType:  ResType;
  590.   pInt:      INTEGER;
  591.   pIntIs:    TResIdOrIndex);
  592. VAR
  593.   sName:     Str255;
  594.   sResLoad:  BOOLEAN;
  595.   {----------------------}
  596.   PROCEDURE  CommentWhich;
  597.   BEGIN
  598.   CommentBegins;
  599.   WryteType(pResType);
  600.   WryteChar(' ');
  601.   WryteNbr (pInt,1);
  602.   IF  (pIntIs = Index) THEN
  603.     Wryte  (' (indexed)');
  604.   WryteEoln;
  605.   END;
  606.   {----------------------}
  607. BEGIN
  608. WITH pRsrcPtr^ DO
  609.   BEGIN
  610.   IF  (fFlag <> kRsrcIsInitd) THEN
  611.     BEGIN
  612.     ErrorMsg('Logic error using GetRsrc',4);
  613.     AwaitKeypress;
  614.     ExitSecurityPatrol;
  615.     END;
  616.   fResType := pResType;
  617.   fResId   := pInt;
  618.   sResLoad := (TWordPtr(kResLoad)^ <> 0);
  619.   IF  (gActiveSelf OR gActiveSys) THEN
  620.     SetResLoad(FALSE);
  621.   IF  (pIntIs = Index) THEN
  622.     BEGIN
  623.     IF  gOption[eTrace] THEN
  624.       TraceRsrc('About to get ind',pRsrcPtr);
  625.     fHdl := Get1IndResource(pResType,pInt);
  626.     END
  627.   ELSE
  628.     BEGIN
  629.     IF  gOption[eTrace] THEN
  630.       TraceRsrc('About to get',pRsrcPtr);
  631.     fHdl := Get1Resource(pResType,pInt);
  632.     END;
  633.   IF  sResLoad THEN
  634.     BEGIN
  635.     IF  (gActiveSelf OR gActiveSys) THEN
  636.       SetResLoad(TRUE);
  637.     IF  (fHdl = NIL)
  638.     OR (ORD4(fHdl) = -1) THEN
  639.       BEGIN
  640.       gError := ResError;
  641.       ErrorOSErr('Couldn’t get resource');
  642.       CommentWhich;
  643.       InitRsrc(pRsrcPtr);
  644.       EXIT(GetRsrc);
  645.       END;
  646.     fFlag := kRsrcHdlValid;
  647.     fResAttrs := GetResAttrs(fHdl);
  648.     IF  (ResError <> NoErr) THEN
  649.       fResAttrs := -1;
  650.     IF  (fHdl^ = NIL) THEN
  651.       BEGIN
  652.       LoadResource(fHdl);
  653.       fLoaded := eWeLoadedIt;
  654.       IF  gOption[eTrace] THEN
  655.         Trace('We loaded it');
  656.       END
  657.     ELSE
  658.       BEGIN
  659.       fLoaded := eAlreadyLoaded;
  660.       IF  gOption[eTrace] THEN
  661.         Trace('Already loaded');
  662.       END;
  663.     IF  (fHdl^ = NIL) THEN
  664.       BEGIN
  665.       gError := ResError;
  666.       IF  (gError <> NoErr) THEN
  667.         BEGIN
  668.         ErrorMsg('Couldn’t load resource',0);
  669.         IF  (gError = memFullErr) THEN
  670.           ErrorMsg('No room in heap zone',1)
  671.         ELSE
  672.           ErrorOSErr('');
  673.         CommentWhich;
  674.         ReleaseRsrc(pRsrcPtr);
  675.         EXIT(GetRsrc);
  676.         END;
  677.       END;
  678.     fSize := SizeResource(fHdl);
  679.     END
  680.   ELSE
  681.     BEGIN
  682.     fFlag   := kRsrcHdlValid;
  683.     fSize   := MaxSizeRsrc(fHdl);
  684.     fLoaded := eNotYet;
  685.     IF  gOption[eTrace] THEN
  686.       Trace('No-load get, loaded not yet');
  687.     END;
  688.   IF  (pIntIs = Index) THEN
  689.     BEGIN
  690.     GetResInfo(fHdl,fResId,fResType,sName);
  691.     gError := ResError;
  692.     IF  (gError <> NoErr) THEN
  693.       BEGIN
  694.       ErrorOSErr('Couldn’t get resource id');
  695.       CommentWhich;
  696.       ReleaseRsrc(pRsrcPtr);
  697.       EXIT(GetRsrc);
  698.       END;
  699.     END;
  700.   IF  sResLoad THEN
  701.     BEGIN
  702.     fState := HGetState(fHdl);
  703.     IF ((fResType = 'CODE')
  704.     AND (fResId   = 0)) THEN
  705.       BEGIN
  706.       MoveHHi(fHdl);
  707.       HLock  (fHdl);
  708.       END
  709.     ELSE
  710.       HNoPurge(fHdl);
  711.     END;
  712.   END;
  713. IF  gOption[eTrace] THEN
  714.   TraceRsrc('Got',pRsrcPtr);
  715. INC(gCounts.fResources);
  716. INC(gTotals.fResources);
  717. END;
  718. {-------------------------------------------}
  719. PROCEDURE  InitGlobals;
  720. VAR
  721.   sGetHdl:   DialogTHndl;
  722.   sGetSize:  Point;
  723.   sPutHdl:   DialogTHndl;
  724.   sPutSize:  Point;
  725.   sScrnSize: Point;
  726. BEGIN
  727. ZeroOutRange(@gAAGlobals,@gZZGlobals);
  728. gCurrIOBuffer := NewPtr(kIOBufferSize);
  729. InitRsrc(@gCode0);
  730. InitRsrc(@gCurrRsrc);
  731. gEvtMask := 
  732.   everyEvent - (updateMask + activMask);
  733. GetPort(gGrafPtr);
  734. gInd      := '    ';
  735.  
  736. sGetHdl := 
  737.   DialogTHndl(GetResource('DLOG',getDlgID));
  738. IF  (sGetHdl = NIL)
  739. OR  (LONGINT(sGetHdl) = -1) THEN
  740.   SetPt(sGetSize,304,104)
  741. ELSE
  742.   BEGIN
  743.   IF  (sGetHdl^ = NIL) THEN
  744.     LoadResource(Handle(sGetHdl));
  745.   sGetSize := sGetHdl^^.boundsRect.botRight;
  746.   ReleaseResource(Handle(sGetHdl));
  747.   END;
  748.  
  749. sPutHdl := 
  750.   DialogTHndl(GetResource('DLOG',putDlgID));
  751. IF  (sPutHdl = NIL)
  752. OR  (LONGINT(sPutHdl) = -1) THEN
  753.   SetPt(sPutSize,348,136)
  754. ELSE
  755.   BEGIN
  756.   IF  (sPutHdl^ = NIL) THEN
  757.     LoadResource(Handle(sPutHdl));
  758.   sPutSize := sPutHdl^^.boundsRect.botRight;
  759.   ReleaseResource(Handle(sPutHdl));
  760.   END;
  761.  
  762. WITH gGrafPtr^.portBits.bounds DO
  763.   BEGIN
  764.   sScrnSize.h := right-left;
  765.   sScrnSize.v := bottom-top;
  766.   END;
  767. gSFGetPt.h := (sScrnSize.h-sGetSize.h) DIV 2;
  768. gSFGetPt.v := (sScrnSize.v-sGetSize.v) DIV 2;
  769. gSFPutPt.h := (sScrnSize.h-sPutSize.h) DIV 2;
  770. gSFPutPt.v := (sScrnSize.v-sPutSize.v) DIV 2;
  771. END;
  772. {-------------------------------------------}
  773. PROCEDURE  InitRsrc
  774.   (pRsrcPtr: TRsrcPtr);
  775. BEGIN
  776. ZeroOut(Ptr(pRsrcPtr),SIZEOF(TRsrcRec));
  777. pRsrcPtr^.fFlag := kRsrcIsInitd;
  778. END;
  779. {-------------------------------------------}
  780. FUNCTION   JTEIsValid
  781.   (pJTEPtr:  TJTEPtr)
  782.   :          BOOLEAN;
  783. VAR
  784.   sCode:     TRsrcRec;
  785. BEGIN
  786. IF  gOption[eTrace] THEN
  787.   Trace('JTEIsValid');
  788. JTEIsValid := FALSE;
  789. WITH pJTEPtr^, sCode DO
  790.   BEGIN
  791.   InitRsrc(@sCode);
  792.   SetResLoad(FALSE);
  793.   GetRsrc(@sCode,'CODE',fSegId,ResId);
  794.   SetResLoad(TRUE);
  795.   IF  (fFlag <> kRsrcHdlValid) THEN
  796.     EXIT(JTEIsValid);
  797.   JTEIsValid := 
  798.     (fSkip3F3C  = $3F3C)  AND
  799.     (fSegId     > 0)      AND
  800.     (fSkipA9F0  = -22032) AND  { $A9F0 }
  801.     (fSize      > 0);
  802.   ReleaseRsrc(@sCode);
  803.   END;
  804. END;
  805. {-------------------------------------------}
  806. PROCEDURE  ListCounts
  807.   (pPtr:     TCountsPtr);
  808. BEGIN
  809. IF  gOption[eTrace] THEN
  810.   Trace('CountsListing');
  811. WITH pPtr^ DO
  812.   BEGIN
  813.   WryteLn ('Files:');
  814.   WryteNbr(fFiles,    6);
  815.   WryteLn (' processed');
  816.   WryteNbr(fExamined,6);
  817.   WryteLn (' examined');
  818.   WryteNbr(fDeleted,  6);
  819.   WryteLn (' deleted');
  820.   WryteLn ('Resources:');
  821.   WryteNbr(fResources,6);
  822.   WryteLn (' processed');
  823.   WryteNbr(fInfected, 6);
  824.   WryteLn (' infected');
  825.   WryteNbr(fRemoved,  6);
  826.   WryteLn (' removed');
  827.   Wryte   ('Currently available memory is ');
  828.   WryteNbr(MemAvail DIV 1024,1);
  829.   WryteLn ('K.');
  830.   PauseBriefly;
  831.   END;
  832. END;
  833. {-------------------------------------------}
  834. PROCEDURE  LookForKnownViruses;
  835. VAR
  836.   sWeUsedToBeInfected: BOOLEAN;
  837.   {--------------------}
  838.   PROCEDURE  Get1stCode;
  839.   BEGIN
  840.   WITH TJTHdl(gCode0.fHdl)^^.fJTEntry[1] DO
  841.     BEGIN
  842.     GetRsrc(@gCurrRsrc,'CODE',fSegId,ResId);
  843.     IF  (gCurrRsrc.fFlag<>kRsrcHdlValid) THEN
  844.       BEGIN
  845.       ErrorInfected('Couldn’t get 1st CODE');
  846.       InitRsrc(@gCurrRsrc);
  847.       EXIT(LookForKnownViruses);
  848.       END;
  849.     END;
  850.   END;
  851.   {--------------------}
  852. BEGIN
  853. IF  gOption[eTrace] THEN
  854.   Trace('LookForKnownViruses');
  855. sWeUsedToBeInfected := FALSE;
  856. Get1stCode;
  857. WITH gCurrRsrc DO
  858.   BEGIN
  859.   LookForVirus_nVIR;
  860.   IF  fInfected THEN
  861.     BEGIN
  862.     CountInfected;
  863.     IF  fKnown AND (fSize = 372) THEN
  864.       ErrorInfected('nVIR 372 virus')
  865.     ELSE IF fKnown AND (fSize = 422) THEN
  866.       ErrorInfected('nVIR 422 virus')
  867.     ELSE
  868.       BEGIN
  869.       ErrorInfected('New nVIR virus!');
  870.       gFgPrTitle := '';
  871.       CommentFgPrRsrc(@gCurrRsrc);
  872.       END;
  873.     IF  Disinfected_nVIR THEN
  874.       sWeUsedToBeInfected := TRUE;
  875.     Get1stCode;
  876.     END;
  877.   LookForVirus_Scores;
  878.   IF  fKnown AND fInfected THEN
  879.     BEGIN
  880.     CountInfected;
  881.     ErrorInfected('Scores virus');
  882.     IF  Disinfected_Scores THEN
  883.       sWeUsedToBeInfected := TRUE;
  884.     END
  885.   ELSE
  886.     ReleaseRsrc(@gCurrRsrc);
  887.   END;
  888. IF  sWeUsedToBeInfected THEN
  889.   LookForKnownViruses;
  890. END;
  891. {-------------------------------------------}
  892. PROCEDURE  PatrolBegins;
  893. BEGIN
  894. IF  gOption[eTrace] THEN
  895.   Trace('PatrolBegins');
  896. WryteEoln;
  897. WryteLn('*******************************');
  898. ZeroOut(@gCounts,SIZEOF(TCountsRec));
  899. GetDateTime(gSecsBegins);
  900. END;
  901. {-------------------------------------------}
  902. PROCEDURE  PatrolEnds;
  903. VAR
  904.   sMins:     INTEGER;
  905.   sSecs:     INTEGER;
  906. BEGIN
  907. GetDateTime(gSecsEnds);
  908. sSecs := gSecsEnds - gSecsBegins;
  909. sMins := sSecs DIV 60;
  910. sSecs := sSecs - (sMins * 60);
  911. WryteEoln;
  912. WryteLn('*******************************');
  913. WryteEoln;
  914. Wryte   ('End of patrol that took ');
  915. WryteNbr(sMins,1);
  916. WryteChar(':');
  917. IF  (sSecs < 10) THEN
  918.   BEGIN
  919.   WryteChar('0');
  920.   WryteNbr (sSecs,1);
  921.   END
  922. ELSE
  923.   WryteNbr (sSecs,2);
  924. WryteEoln;
  925. ListCounts(@gCounts);
  926. END;
  927. {-------------------------------------------}
  928. PROCEDURE  PauseBriefly;
  929. VAR
  930.   sTicks:    LONGINT;
  931. BEGIN
  932. Delay(120,sTicks);
  933. END;
  934. {-------------------------------------------}
  935. PROCEDURE  ProcessCodes;
  936. VAR
  937.   i:           INTEGER;
  938.   sNbrEntries: INTEGER;
  939.   sPrevId:     INTEGER;
  940.   sWeirdCode0: BOOLEAN;
  941.   {------------------------}
  942.   PROCEDURE    CommentWhere;
  943.   BEGIN
  944.   CommentBegins;
  945.   Wryte   ('At entry ');
  946.   WryteNbr(i,1);
  947.   WryteEoln;
  948.   END;
  949.   {------------------------}
  950. BEGIN
  951. IF  gOption[eTrace] THEN
  952.   Trace('ProcessCodes');
  953. GetRsrc(@gCode0,'CODE',0,ResId);
  954. IF  (gCode0.fFlag <> kRsrcHdlValid) THEN
  955.   BEGIN
  956.   ErrorMsg('Code rsrcs without CODE 0',1);
  957.   EXIT(ProcessCodes);
  958.   END;
  959. IF  NOT(Code0IsValid) THEN
  960.   BEGIN
  961.   ErrorMsg('Unexpected CODE 0 values',1);
  962.   ReleaseRsrc(@gCode0);
  963.   EXIT(ProcessCodes);
  964.   END;
  965. LookForKnownViruses;
  966. WITH TJTHdl(gCode0.fHdl)^^ DO
  967.   BEGIN
  968.   sNbrEntries := fNbrBytesInTable DIV 8;
  969.   sPrevId     := 1;
  970.   sWeirdCode0 := 
  971.     (COPY(gCurrFilename,1,9)='Red Ryder') OR
  972.     (COPY(gCurrFilename,1,6)='Canvas'   ) OR
  973.     (COPY(gCurrFilename,1,9)='PageMaker');
  974.   FOR i := 1 TO sNbrEntries DO
  975.     WITH fJTEntry[i] DO
  976.       BEGIN
  977.       IF  (fSkip3F3C  = $3F3C)
  978.       AND (fSegId     = sPrevId)
  979.       AND (fSkipA9F0  = -22032) THEN
  980.         CYCLE;
  981.       AbortPatrolIfCmdPeriodPressed;
  982.       IF  gAbortPatrol THEN
  983.         LEAVE;
  984.       IF  NOT(JTEIsValid(@fJTEntry[i])) THEN
  985.         BEGIN
  986.         ErrorMsg('CODE 0 has invalid JTE',1);
  987.         CommentWhere;
  988.         LEAVE;
  989.         END;
  990.       IF  sWeirdCode0 THEN
  991.         BEGIN
  992.         sPrevId := fSegId;
  993.         CYCLE;
  994.         END;
  995.       IF  (fSegId < sPrevId) THEN
  996.         BEGIN
  997.         ErrorMsg('JT not ascending',1);
  998.         CommentWhere;
  999.         LEAVE;
  1000.         END;
  1001.       INC(sPrevId);
  1002.       IF  (fSegId = sPrevId) THEN
  1003.         CYCLE;
  1004.       ErrorMsg('JT skips ResId',1);
  1005.       CommentWhere;
  1006.       LEAVE;
  1007.       END;
  1008.   END;
  1009. ReleaseRsrc(@gCode0);
  1010. END;
  1011. {-------------------------------------------}
  1012. PROCEDURE  ProcessFile;
  1013. VAR
  1014.   sSaveC1T:  INTEGER;
  1015.   {----------------------------}
  1016.   PROCEDURE  ExitIfCantReadFork;
  1017.   BEGIN
  1018.   IF  (gError <> NoErr) THEN
  1019.     BEGIN
  1020.     IF  (gError = eofErr) THEN
  1021.       { no resource fork }
  1022.     ELSE IF  (gError = fnfErr) THEN
  1023.       ErrorMsg('File not found',1)
  1024.     ELSE IF  (gError = nsvErr) THEN
  1025.       ErrorMsg('No such volume',1)
  1026.     ELSE IF  (gError = opWrErr) THEN
  1027.       ErrorMsg(CONCAT('Already in use.  ',
  1028.         '(Don’t use under MultiFinder!)'),1)
  1029.     ELSE
  1030.       ErrorOSErr('Couldn’t open file');
  1031.     gError := NoErr;
  1032.     EXIT(ProcessFile);
  1033.     END;
  1034.   END;
  1035.   {----------------------------}
  1036. BEGIN
  1037. IF  gOption[eTrace] THEN
  1038.   Trace('ProcessFile');
  1039. AbortPatrolIfCmdPeriodPressed;
  1040. IF  gAbortPatrol THEN
  1041.   EXIT(ProcessFile);
  1042. INC(gCounts.fFiles);
  1043. INC(gTotals.fFiles);
  1044. gInfected                   := FALSE;
  1045. gInfectedWritten            := FALSE;
  1046. gReportFlags.fWroteFilename := FALSE;
  1047. gScreenFlags.fWroteFilename := FALSE;
  1048. IF  gOption[eLList] THEN
  1049.   WryteFilename
  1050. ELSE
  1051.   WryteFilenameToScreenOnlyForNow;
  1052. IF  (LENGTH(gCurrFilename) > 0) THEN
  1053.   IF (gCurrFilename[1] = '.') THEN
  1054.     BEGIN
  1055.     ErrorMsg('Filename begins with “.”',1);
  1056.     EXIT(ProcessFile);
  1057.     END;
  1058. IF  gActiveSelf AND NOT(kProcessSelf) THEN
  1059.   EXIT(ProcessFile);
  1060. gCurrEOF := -1;
  1061. gError := FSOpen(gCurrFilename,gCurrWDRefNum,
  1062.                  gCurrRefNum);
  1063. ExitIfCantReadFork;
  1064. gError := GetEOF(gCurrRefNum,gCurrEOF);
  1065. IF  (gError = NoErr) THEN
  1066.   BEGIN
  1067.   WITH gCurrFInfo DO
  1068.     IF  (COPY(gCurrFilename,1,7)='MacsBug') 
  1069.     OR  (fdType = 'RELB') 
  1070.     OR  (fdType = 'OBJ ') THEN
  1071.       IF  NOT(KnownDataFork) THEN
  1072.         CommentFgPrData;
  1073.   gError := FSClose(gCurrRefNum);
  1074.   IF  (gError <> NoErr) THEN
  1075.     ErrorOSErr('Couldn’t close data fork');
  1076.   END
  1077. ELSE
  1078.   ErrorOSErr('Couldn’t GetEOF');
  1079. IF  gActiveSelf THEN
  1080.   BEGIN
  1081.   gCurrRefNum := TWordPtr(kCurApRefNum)^;
  1082.   gError  := NoErr;
  1083.   END
  1084. ELSE IF  gActiveSys THEN
  1085.   BEGIN
  1086.   gCurrRefNum := TWordPtr(kSysMap)^;
  1087.   gError  := NoErr;
  1088.   END
  1089. ELSE
  1090.   BEGIN
  1091.   SetResLoad(FALSE);
  1092.   gCurrRefNum := OpenRFPerm(gCurrFilename,
  1093.                             gCurrWDRefNum,
  1094.                             fsRdWrPerm);
  1095.   gError  := ResError;
  1096.   SetResLoad(TRUE);
  1097.   ExitIfCantReadFork;
  1098.   END;
  1099. IF  (gCurrRefNum <> CurResFile) THEN
  1100.   BEGIN
  1101.   UseResFile(gCurrRefNum);
  1102.   gError := ResError;
  1103.   IF  (gError <> NoErr) THEN
  1104.     BEGIN
  1105.     ErrorOSErr('Couldn’t use resource fork');
  1106.     gError := NoErr; 
  1107.     EXIT(ProcessFile);
  1108.     END;
  1109.   END;
  1110. INC(gCounts.fExamined);
  1111. INC(gTotals.fExamined);
  1112. IF  (Count1Resources('CODE') > 0) THEN
  1113.   ProcessCodes;
  1114. gFgPrTitle := 'Unknown Resource(s):';
  1115. ProcessRsrcs('ADBS',@Process_ADBS);
  1116. ProcessRsrcs('CACH',@Process_CACH);
  1117. ProcessRsrcs('CDEF',@Process_CDEF);
  1118. ProcessRsrcs('DATA',@Process_DATA);
  1119. ProcessRsrcs('DRVR',@Process_DRVR);
  1120. ProcessRsrcs('DSAT',@Process_DSAT);
  1121. ProcessRsrcs('FKEY',@Process_FKEY);
  1122. ProcessRsrcs('FMTR',@Process_FMTR);
  1123. ProcessRsrcs('INIT',@Process_INIT);
  1124. ProcessRsrcs('LDEF',@Process_LDEF);
  1125. ProcessRsrcs('MBDF',@Process_MBDF);
  1126. ProcessRsrcs('MDEF',@Process_MDEF);
  1127. ProcessRsrcs('MMAP',@Process_MMAP);
  1128. ProcessRsrcs('NBPC',@Process_NBPC);
  1129. ProcessRsrcs('PACK',@Process_PACK);
  1130. ProcessRsrcs('PDEF',@Process_PDEF);
  1131. ProcessRsrcs('PTCH',@Process_PTCH);
  1132. ProcessRsrcs('ROv#',@Process_ROvList);
  1133. ProcessRsrcs('ROvr',@Process_ROvr);
  1134. ProcessRsrcs('SERD',@Process_SERD);
  1135. ProcessRsrcs('WDEF',@Process_WDEF);
  1136. ProcessRsrcs('XCMD',@Process_XCMD);
  1137. ProcessRsrcs('XFCN',@Process_XFCN);
  1138. ProcessRsrcs('atpl',@Process_atpl);
  1139. ProcessRsrcs('boot',@Process_boot);
  1140. ProcessRsrcs('cdev',@Process_cdev);
  1141. ProcessRsrcs('mppc',@Process_mppc);
  1142. ProcessRsrcs('snth',@Process_snth);
  1143. ProcessRsrcs('view',@Process_view);
  1144. IF  gOption[eFgPr] THEN
  1145.   BEGIN
  1146.   gFgPrTitle := 'Fingerprint(s):';
  1147.   ProcessRsrcs('ADBS',@ProcessCurrRsrc);
  1148.   ProcessRsrcs('CACH',@ProcessCurrRsrc);
  1149.   ProcessRsrcs('CDEF',@ProcessCurrRsrc);
  1150.   IF  gOption[eFgPrC] THEN
  1151.     ProcessRsrcs('CODE',@ProcessCurrRsrc);
  1152.   ProcessRsrcs('DATA',@ProcessCurrRsrc);
  1153.   ProcessRsrcs('DRVR',@ProcessCurrRsrc);
  1154.   ProcessRsrcs('DSAT',@ProcessCurrRsrc);
  1155.   ProcessRsrcs('FKEY',@ProcessCurrRsrc);
  1156.   ProcessRsrcs('FMTR',@ProcessCurrRsrc);
  1157.   ProcessRsrcs('INIT',@ProcessCurrRsrc);
  1158.   ProcessRsrcs('LDEF',@ProcessCurrRsrc);
  1159.   ProcessRsrcs('MBDF',@ProcessCurrRsrc);
  1160.   ProcessRsrcs('MDEF',@ProcessCurrRsrc);
  1161.   ProcessRsrcs('MMAP',@ProcessCurrRsrc);
  1162.   ProcessRsrcs('NBPC',@ProcessCurrRsrc);
  1163.   ProcessRsrcs('PACK',@ProcessCurrRsrc);
  1164.   ProcessRsrcs('PDEF',@ProcessCurrRsrc);
  1165.   ProcessRsrcs('PTCH',@ProcessCurrRsrc);
  1166.   ProcessRsrcs('ROv#',@ProcessCurrRsrc);
  1167.   ProcessRsrcs('ROvr',@ProcessCurrRsrc);
  1168.   ProcessRsrcs('SERD',@ProcessCurrRsrc);
  1169.   ProcessRsrcs('WDEF',@ProcessCurrRsrc);
  1170.   ProcessRsrcs('XCMD',@ProcessCurrRsrc);
  1171.   ProcessRsrcs('XFCN',@ProcessCurrRsrc);
  1172.   ProcessRsrcs('atpl',@ProcessCurrRsrc);
  1173.   ProcessRsrcs('boot',@ProcessCurrRsrc);
  1174.   ProcessRsrcs('cdev',@ProcessCurrRsrc);
  1175.   ProcessRsrcs('mppc',@ProcessCurrRsrc);
  1176.   ProcessRsrcs('snth',@ProcessCurrRsrc);
  1177.   ProcessRsrcs('view',@ProcessCurrRsrc);
  1178.   ProcessRsrcs('nVIR',@ProcessCurrRsrc);
  1179.   END;
  1180. IF  gActiveSelf OR gActiveSys THEN
  1181.   EXIT(ProcessFile);
  1182. sSaveC1T := Count1Types;
  1183. CloseResFile(gCurrRefNum);
  1184. IF  NOT(gInfected) THEN
  1185.   EXIT(ProcessFile);
  1186. WITH gCurrFInfo DO
  1187.   BEGIN
  1188.   IF ((gCurrFilename = 'Note Pad File')
  1189.   OR  (gCurrFilename = 'Scrapbook File'))
  1190.   AND (fdCreator = 'ZSYS')
  1191.   AND gOption[eRmVir] THEN
  1192.     BEGIN
  1193.     fdType    := 'ZSYS';
  1194.     fdCreator := 'MACS';
  1195.     fdFlags   := 4096;
  1196.     gError    := SetFInfo(gCurrFilename,
  1197.                           gCurrWDRefNum,
  1198.                           gCurrFInfo);
  1199.     IF  (gError = NoErr) THEN
  1200.       ErrorMsg('Reset to system document',0)
  1201.     ELSE
  1202.       ErrorOSErr('FInfo not reset');
  1203.     EXIT(ProcessFile);
  1204.     END;
  1205.   END;
  1206. IF  (gCurrEOF <> 0) THEN
  1207.   BEGIN
  1208.   ErrorMsg('File still has data fork',0);
  1209.   ErrorMsg('File not deleted',1);
  1210.   EXIT(ProcessFile);
  1211.   END;
  1212. IF  (sSaveC1T <> 0) THEN
  1213.   BEGIN
  1214.   ErrorMsg('File still has resources',0);
  1215.   ErrorMsg('File not deleted',1);
  1216.   EXIT(ProcessFile);
  1217.   END;
  1218. ErrorMsg('File emptied',0);
  1219. gError := 
  1220.   FSDelete(gCurrFilename,gCurrWDRefNum);
  1221. IF  (gError = NoErr) THEN
  1222.   BEGIN
  1223.   gCurrFileDeleted := TRUE;
  1224.   INC(gCounts.fDeleted);
  1225.   INC(gTotals.fDeleted);
  1226.   ErrorMsg('File deleted',1);
  1227.   END
  1228. ELSE
  1229.   ErrorOSErr('File not deleted');
  1230. END;
  1231. {-------------------------------------------}
  1232. PROCEDURE  ProcessRsrcs
  1233.   (pResType: ResType;
  1234.   pProcPtr:  ProcPtr);
  1235. VAR
  1236.   i:         INTEGER;
  1237.   sIdx:      INTEGER;
  1238. BEGIN
  1239. IF  gOption[eTrace] THEN
  1240.   Trace('ProcessRsrcs');
  1241. WITH gCurrRsrc DO
  1242.   BEGIN
  1243.   sIdx := 1;
  1244.   FOR i := 1 TO Count1Resources(pResType) DO
  1245.     BEGIN
  1246.     AbortPatrolIfCmdPeriodPressed;
  1247.     IF  gAbortPatrol THEN
  1248.       LEAVE;
  1249.     GetRsrc(@gCurrRsrc,pResType,sIdx,Index);
  1250.     IF  (fFlag <> kRsrcHdlValid) THEN
  1251.       BEGIN
  1252.       INC(sIdx);
  1253.       CYCLE;
  1254.       END;
  1255.     CallProcPtr(pProcPtr);
  1256.     IF  fInfected THEN
  1257.       BEGIN
  1258.       CountInfected;
  1259.       ErrorInfected('');
  1260.       CommentRsrcBegins(@gCurrRsrc);
  1261.       WryteLn(' is an infection');
  1262.       IF  RemovedRsrc(@gCurrRsrc) THEN
  1263.         BEGIN
  1264.         ErrorMsg('Removed',0);
  1265.         CYCLE;
  1266.         END;
  1267.       ErrorMsg('Not removed',1);
  1268.       INC(sIdx);
  1269.       CYCLE;
  1270.       END;
  1271.     IF  NOT(fKnown) THEN
  1272.       CommentFgPrRsrc(@gCurrRsrc);
  1273.     ReleaseRsrc(@gCurrRsrc);
  1274.     INC(sIdx);
  1275.     END;
  1276.   END;
  1277. END;
  1278. {-------------------------------------------}
  1279. PROCEDURE  ReleaseRsrc
  1280.   (pRsrcPtr: TRsrcPtr);
  1281. BEGIN
  1282. WITH pRsrcPtr^ DO
  1283.   BEGIN
  1284.   IF  (fFlag <> kRsrcHdlValid) THEN
  1285.     BEGIN
  1286.     ErrorMsg('Error using ReleaseRsrc',4);
  1287.     AwaitKeypress;
  1288.     ExitSecurityPatrol;
  1289.     END;
  1290.   IF  gOption[eTrace] THEN
  1291.     TraceRsrc('About to release',pRsrcPtr);
  1292.   IF  (gActiveSelf OR gActiveSys) THEN
  1293.     IF  gOption[eTrace] THEN
  1294.       Trace('Not Released')
  1295.     ELSE
  1296.   ELSE
  1297.     BEGIN
  1298.     HSetState(fHdl,fState);
  1299.     ReleaseResource(fHdl);
  1300.     IF  gOption[eTrace] THEN
  1301.       Trace('Released');
  1302.     END;
  1303.   InitRsrc(pRsrcPtr);
  1304.   END;
  1305. END;
  1306. {-------------------------------------------}
  1307. FUNCTION   RemovedRsrc
  1308.   (pRsrcPtr: TRsrcPtr)
  1309.   :          BOOLEAN;
  1310. VAR
  1311.   sBits0and7:LONGINT;
  1312.   {--------------------}
  1313.   PROCEDURE  ExitIfError
  1314.     (pStr:     Str255);
  1315.   BEGIN
  1316.   gError := ResError;
  1317.   IF  (gError <> NoErr) THEN
  1318.     BEGIN
  1319.     ErrorMsg(pStr,0);
  1320.     IF  (gError = wPrErr) THEN
  1321.       ErrorMsg('Disk is locked',0)
  1322.     ELSE
  1323.       ErrorOSErr('');
  1324.     CommentRsrcBegins(pRsrcPtr);
  1325.     WryteLn(' not removed');
  1326.     ReleaseRsrc(pRsrcPtr);
  1327.     EXIT(RemovedRsrc);
  1328.     END;
  1329.   END;
  1330.   {--------------------}
  1331. BEGIN
  1332. RemovedRsrc := FALSE;
  1333. IF  gOption[eTrace] THEN
  1334.   Trace('RemovedRsrc');
  1335. AbortPatrolIfCmdPeriodPressed;
  1336. IF  gAbortPatrol
  1337. OR  NOT(gOption[eRmVir]) THEN
  1338.   BEGIN
  1339.   ReleaseRsrc(pRsrcPtr);
  1340.   EXIT(RemovedRsrc);
  1341.   END;
  1342. WITH pRsrcPtr^ DO
  1343.   BEGIN
  1344.   IF  (fFlag <> kRsrcHdlValid) THEN
  1345.     BEGIN
  1346.     ErrorMsg('Error using RemovedRsrc',4);
  1347.     AwaitKeypress;
  1348.     ExitSecurityPatrol;
  1349.     END;
  1350.   IF  gOption[eTrace] THEN
  1351.     BEGIN
  1352.     TraceRsrc('About to remove',pRsrcPtr);
  1353.     AbortPatrolIfCmdPeriodPressed;
  1354.     IF  gAbortPatrol THEN
  1355.       EXIT(RemovedRsrc);
  1356.     END;
  1357.   IF  NOT(fInfected) THEN
  1358.     BEGIN
  1359.     ErrorMsg('Tried to remove uninfected',4);
  1360.     AwaitKeypress;
  1361.     ExitSecurityPatrol;
  1362.     END;
  1363.   IF  kZeroOutVirs AND (fHdl^ <> NIL) THEN
  1364.     BEGIN
  1365.     ZeroOut(fHdl^,fSize);
  1366.     ChangedResource(fHdl);
  1367.     gError := ResError;
  1368.     IF  (gError = NoErr) THEN
  1369.       BEGIN
  1370.       WriteResource(fHdl);
  1371.       gError := ResError;
  1372.       IF  (gError <> NoErr) THEN
  1373.         ErrorOSErr('Couldn’t WriteResource');
  1374.       END
  1375.     ELSE
  1376.       ErrorOSErr('Couldn’t ChangedResource');
  1377.     END;
  1378.   sBits0and7 := BAnd(fResAttrs,$81);
  1379.   SetResAttrs(fHdl,LoWord(sBits0and7));
  1380.   RmveResource(fHdl);
  1381.   ExitIfError('Couldn’t remove resource');
  1382.   UpdateResFile(gCurrRefNum);
  1383.   ExitIfError('Couldn’t update res file');
  1384.   DisposHandle(fHdl);
  1385.   InitRsrc(pRsrcPtr);
  1386.   RemovedRsrc := TRUE;
  1387.   IF  gOption[eTrace] THEN
  1388.     Trace('RemovedRsrc successful');
  1389.   END;
  1390. INC(gCounts.fRemoved);
  1391. INC(gTotals.fRemoved);
  1392. END;
  1393. {-------------------------------------------}
  1394. PROCEDURE  ShortHexDump
  1395.   (pPtr:     Ptr;
  1396.   pNbrBytes: SignedByte);
  1397. VAR
  1398.   i:         INTEGER;
  1399.   sCh1,sCh2: LONGINT;
  1400.   sDigit:    LONGINT;
  1401.   sIdx:      Ptr;
  1402. BEGIN
  1403. sIdx  := pPtr;
  1404. FOR i := 1 TO pNbrBytes DO
  1405.   BEGIN
  1406.   sDigit := ORD4(sIdx^);
  1407.   sCh1   := BSR(BAnd(sDigit,$F0),4);
  1408.   sCh2   :=     BAnd(sDigit,$0F);
  1409.   IF  sCh1 > 9 THEN
  1410.     WryteChar(CHR(sCh1 + $37))
  1411.   ELSE
  1412.     WryteChar(CHR(sCh1 + $30));
  1413.   IF  sCh2 > 9 THEN
  1414.     WryteChar(CHR(sCh2 + $37))
  1415.   ELSE
  1416.     WryteChar(CHR(sCh2 + $30));
  1417.   INC(LONGINT(sIdx));
  1418.   END;
  1419. END;
  1420. {-------------------------------------------}
  1421. PROCEDURE  Trace
  1422.   (pStr:     Str255);
  1423. BEGIN
  1424. ErrorBegins(pStr);
  1425. ErrorEnds(0);
  1426. END;
  1427. {-------------------------------------------}
  1428. PROCEDURE  TraceNbr
  1429.   (pStr:     Str255;
  1430.   pNbr:      LONGINT);
  1431. BEGIN
  1432. ErrorBegins(pStr);
  1433. WryteNbr(pNbr,1);
  1434. ErrorEnds(0);
  1435. END;
  1436. {-------------------------------------------}
  1437. PROCEDURE  TraceRsrc
  1438.   (pStr:     Str255;
  1439.   pRsrcPtr:  TRsrcPtr);
  1440. BEGIN
  1441. ErrorBegins(pStr);
  1442. WITH pRsrcPtr^ DO
  1443.   BEGIN
  1444.   WryteChar(' ');
  1445.   WryteType(fResType);
  1446.   WryteNbr (fResId,7);
  1447.   END;
  1448. ErrorEnds(0);
  1449. END;
  1450. {-------------------------------------------}
  1451. PROCEDURE  ZeroOut
  1452.   (pStart:   Ptr;
  1453.   pCount:    Size);
  1454. VAR
  1455.   i:         INTEGER;
  1456.   sIdx:      Ptr;
  1457. BEGIN
  1458. sIdx := pStart;
  1459. FOR i := 1 TO pCount DO
  1460.   BEGIN
  1461.   sIdx^ := 0;
  1462.   INC(LONGINT(sIdx));
  1463.   END;
  1464. END;
  1465. {-------------------------------------------}
  1466. PROCEDURE  ZeroOutRange
  1467.   (p1:       Ptr;
  1468.   p2:        Ptr);
  1469. VAR
  1470.   i:         INTEGER;
  1471.   sIdx:      Ptr;
  1472. BEGIN
  1473. IF  (ORD4(p1) < ORD4(p2)) THEN
  1474.   sIdx := p1
  1475. ELSE
  1476.   sIdx := p2;
  1477. FOR i := 1 TO ABS(ORD4(p2)-ORD4(p1))+1 DO
  1478.   BEGIN
  1479.   sIdx^ := 0;
  1480.   INC(LONGINT(sIdx));
  1481.   END;
  1482. END;
  1483. {*******************************************}
  1484. END.